import json
import logging
import os
import re
import shutil
import time
from abc import ABC
from selenium.webdriver.common.by import By
from selenium.webdriver.common.action_chains import ActionChains
from selenium.webdriver import Firefox
from selenium.common.exceptions import NoSuchElementException
import settings
import util


def set_cookie(driver, cookie):
    """
    将 cookie 设置到 driver 中
    """
    try:
        cookie = json.loads(cookie)
        for item in cookie:
            item['sameSite'] = 'None'
            driver.add_cookie(item)
    except Exception as e:
        logging.exception(e)
        raise RuntimeError("设置 cookie失败")


class BaseWorker(object):

    def __enter__(self):
        self.driver = Firefox(executable_path=self.executor_path)
        self.driver.get("http://baijiahao.baidu.com/builder/theme/bjh/login")
        # 设置隐式超时时间
        self.driver.implicitly_wait(2)
        set_cookie(self.driver, self.article["account"]["cookie"])
        self.refresh()
        return self

    def __exit__(self, exc_type, exc_val, exc_tb):
        try:
            if exc_type is None:
                print("分发成功")
                print(self.article)
                util.rewrite(3, self.article["content_id"], "分发成功")
            else:
                print(exc_type, exc_val, repr(exc_tb))
                util.rewrite(4, self.article["content_id"], exc_val)
        except:
            pass
        finally:
            self.destroy()

    def __init__(self, article, executor_path="./chromedriver", config=None):
        if config is None:
            raise RuntimeError("没有配置文件")
        self.config = config
        self.driver = None
        self.article = article
        self.executor_path = executor_path

    def refresh(self):
        """
        设置 cookie 后, 访问发布页面
        :param url: 发布页面的网址
        :return:
        """
        time.sleep(2)
        self.driver.get(self.config["URL_START_POINT"])
        self.driver.maximize_window()

    def write_content(self):
        """
        上传文字
        :return:
        """
        content = self.article['content']
        self.driver.find_element_by_css_selector(".input-box .cheetah-input").send_keys(content)

    def upload_video(self):
        """
        上传视频
        :return:
        """
        video_path = self.article["video_path"]
        size = util.file_size(video_path)
        self.log(video_path + "\t" + str(size) + "MB")
        # 上传视频
        self.driver.find_element(By.CSS_SELECTOR, self.config["SELECTOR_CSS_VIDEO"]).send_keys(video_path)
        return size * settings.UPLOAD_TIME_MULTIPLE

    def upload_cover(self):
        """
        上传封面
        """
        self.driver.find_element_by_css_selector(".client_pages_edit_cover_uploaderView.bjh-image-view").click()
        time.sleep(2)
        img_path = self.article["img_path"]
        # 点击上传封面
        self.driver.find_element_by_xpath('//div[text()="上传封面"]').click()
        time.sleep(3)
        self.driver.find_element_by_css_selector(
            ".cheetah-upload.cheetah-upload-select.cheetah-upload-select-text>span>input[type='file']").send_keys(
            img_path)
        time.sleep(4)
        self.driver.find_element_by_css_selector(".cheetah-modal-footer .cheetah-btn.cheetah-btn-primary").click()

    def set_tag(self):
        """
        设置标签
        """
        if self.article['tag'] is not None:
            self.driver.find_element_by_css_selector(".tags-container ._edit-video-topic-input").click()
            time.sleep(1)
            self.driver.find_element_by_css_selector(".tags-container ._edit-video-topic-input").send_keys(
                self.article['tag'])
            time.sleep(2)
            self.driver.find_elements_by_css_selector(".topic-list .topic-item")[0].click()

    def scroll_down(self, height):
        """
        滚动页面
        :param height:  滚动的距离
        :return:
        """
        self.driver.execute_script("document.documentElement.scrollTop=" + height)

    def save(self):
        """
        保存
        """
        self.driver.find_element(By.XPATH, self.config["SELECTOR_XPATH_SAVE"]).click()

    def publish(self):
        """
        发布
        """
        raise NotImplementedError()

    def check_save(self):
        """
        检查是否保存成功
        """
        for i in range(5):
            # 检查有没有弹出框。
            try:
                modal = self.driver.find_element(By.XPATH, "//div[contains(@class, 'cheetah-public') and contains("
                                                           "@class, 'cheetah-modal')]")
                modal.find_element(By.CSS_SELECTOR, "input.cheetah-checkbox-input").click()
                modal.find_element(By.CSS_SELECTOR, "button.cheetah-btn").click()
            except NoSuchElementException:
                pass

            if self.driver.current_url != self.config["URL_START_POINT"]:
                break
            time.sleep(2)
        else:
            raise RuntimeError(settings.FEEDBACK["ARTICLE"]["STAY"])

    def set_tips(self):
        # 标签
        tag = self.article['keywords']
        if tag is not None or tag != '':
            self.driver.find_element_by_css_selector(".client_components_tagInput .tags-container input").send_keys(tag)
            time.sleep(2)
            self.driver.find_elements_by_css_selector(".topic-list .topic-item")[0].click()

    def destroy(self, is_clear=True):
        if is_clear:
            folder = os.path.join(settings.DOWNLOAD_CACHE_DIR, str(self.article["id"]))
            if os.path.isdir(folder):
                shutil.rmtree(folder)
        self.driver.quit()

    def check_publish_count(self):
        """
        检查发布次数
        """
        save_btn = self.driver.find_element(By.XPATH, self.config["SELECTOR_XPATH_SAVE"])
        chains = ActionChains(self.driver)
        chains.move_to_element(save_btn).perform()
        try:
            chains.release(save_btn).perform()
        except:
            pass
        text = self.driver.execute_script('return document.querySelector(".cheetah-tooltip-inner") && '
                                          'document.querySelector(".cheetah-tooltip-inner").innerText || '
                                          '"无法获取到当天可发布天数"')
        match = re.match(r"^今天您还能发(\d+)篇内容$", text)
        if match is None or match.group(1) == '0':
            raise RuntimeError(text)

    @staticmethod
    def log(msg):
        print(msg)


class HorizontalPublishWorker(BaseWorker, ABC):
    """
    横版百家号发布工作类
    """

    def publish(self):
        # self.check_publish_count()
        # 写入内容
        self.write_content()
        # 上传视频
        upload_duration = self.upload_video()

        time.sleep(2)
        self.scroll_down("400")
        time.sleep(2)

        # 设置标签
        self.set_tag()
        time.sleep(2)

        # 上传封面
        self.scroll_down("document.body.scrollHeight")
        self.upload_cover()
        time.sleep(10)

        # 移动到底部
        self.scroll_down("document.body.scrollHeight")
        time.sleep(2)

        # 设置简介
        self.set_desc()
        time.sleep(2)

        # 等待视频上传
        time.sleep(upload_duration)

        # 保存
        self.save()

        # 检查是否保存成功
        self.check_save()

    def set_desc(self):
        """
        设置简介
        """
        content = self.article['content']
        desc_element = self.driver.find_element_by_css_selector("#desc")
        desc_element.clear()
        desc_element.send_keys(content)


class VerticalPublishWorker(BaseWorker, ABC):
    """
    竖版百家号发布工作类
    """

    def publish(self):
        # self.check_publish_count()
        self.write_content()
        time.sleep(2)

        upload_duration = self.upload_video()

        self.set_tag()
        time.sleep(2)

        self.scroll_down("500")
        time.sleep(6)

        self.upload_cover()
        time.sleep(10)

        # 传长封面
        try:
            self.upload_large_cover()
            self.upload_large_cover_again()
        except:
            pass
        time.sleep(3)

        time.sleep(upload_duration)

        self.save()
        
        self.check_save()

    def upload_large_cover(self):
        """
        上传大封面
        """
        self.driver.find_elements_by_xpath('//div[@class = "client_pages_edit_cover one"]')[1].click()
        time.sleep(2)
        img_path = self.article["img_path"]
        # 点击上传封面
        self.driver.find_element_by_xpath('//div[text()="上传封面"]').click()
        time.sleep(3)
        self.driver.find_element_by_css_selector(
            ".cheetah-upload.cheetah-upload-select.cheetah-upload-select-text>span>input[type='file']").send_keys(
            img_path)
        time.sleep(3)
        self.driver.find_element_by_css_selector(".cheetah-modal-footer .cheetah-btn.cheetah-btn-primary").click()

    def upload_large_cover_again(self):
        self.driver.find_element_by_css_selector('.shortvideoclips-info').find_elements_by_css_selector(
            '.shortvideoclips-info-wrapper')[1].find_element_by_css_selector('.action.replace-icon').click()
        time.sleep(2)
        img_path = self.article["img_path"]
        # 点击上传封面
        self.driver.find_element_by_xpath('//div[text()="上传封面"]').click()
        time.sleep(3)
        self.driver.find_element_by_css_selector(
            ".cheetah-upload.cheetah-upload-select.cheetah-upload-select-text>span>input[type='file']").send_keys(
            img_path)
        time.sleep(3)
        # driver.find_element_by_css_selector(".cheetah-modal-content .cheetah-modal-footer
        # .cheetah-btn.cheetah-btn-primary").click()
        tupianbutton = self.driver.find_element_by_css_selector(
            ".cheetah-modal-content .cheetah-modal-footer .cheetah-btn.cheetah-btn-primary")
        ActionChains(self.driver).move_to_element(tupianbutton).perform()
        time.sleep(3)
        tupianbutton.click()
